using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;

namespace Library.WebControls.Ds {
   class Enumerable<T> : IEnumerable<T> {
    internal EnumeratorNode<T> RootNode {
      get { return _instance.RootNode; }
    }
    private readonly Enumerator<T> _instance;
    private int _totalItem;

    public Enumerable() {
      _instance = new Enumerator<T>();
    }

    public EnumeratorNode<T> CurrentNode {
      get { return _instance.CurrentNode; }
    }

    public int TotalItem {
      get { return _totalItem; }
    }

    #region IEnumerable<T> Members

    IEnumerator IEnumerable.GetEnumerator() {
      return GetEnumerator();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator() {
      return GetEnumerator();
    }

    #endregion

    public Enumerator<T> GetEnumerator() {
      _instance.Reset();
      return _instance;
    }

    public void Join(Enumerable<T> enumerable) {
      _instance.Join(enumerable.GetEnumerator());
      _totalItem += enumerable._totalItem;
    }


    public void AddItem(T item) {
      _instance.AddNode(item);
      _totalItem++;
    }

    public T Find(string propertyName, object value) {
      foreach (T t in this) {
        var wraper = new DataSourceWrapper.DataItemWraper(t);
        foreach (PropertyDescriptor p in wraper.PropertyCollection) {
          if (p.Name == propertyName) {
            // ReSharper disable AssignNullToNotNullAttribute
            object v = p.GetValue(t);
            if (v == null) {
              if (value == null)
                return t;
              return default(T);
            }
            if (v.Equals(value))
              // ReSharper restore AssignNullToNotNullAttribute
              return t;
            break;
          }
        }
      }
      return default(T);
    }

    /// <summary>
    /// Remove node in enumrator. if node is curent node, next node replace current node
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public bool RemoveNode(EnumeratorNode<T> node) {
      if (node != null) {
        if (!ReferenceEquals(_instance, node.Rator)) {
          throw new ArgumentException("Can not remove node not belong to current enumerable");
        }
        //break preview note ponter to this node
        node.Preview.Next = node.Next;

        //break preview node of next node
        if (node.Next != null) {
          node.Next.Preview = node.Preview;
        } else //removed node is last note
				{
          _instance.LastNode = node.Preview;
        }

        _totalItem--;
        return true;
      }
      return false;
    }


    public void RemoveCurrentNode() {
      RemoveNode(CurrentNode);
    }

    public BindingList<T> ToBindingList() {
      var list = new BindingList<T>();
      foreach (var t in this) {
        list.Add(t);
      }

      return list;
    }
  }
}